package erwiki.ui.app.parts.attachments.handlers;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.Permission;
import java.security.Principal;
import java.util.Date;

import org.apache.commons.io.FileUtils;
import org.apache.log4j.Logger;
import org.eclipse.core.runtime.IPath;
import org.eclipse.e4.core.di.annotations.Execute;
import org.eclipse.e4.core.services.events.IEventBroker;
import org.eclipse.e4.ui.services.IServiceConstants;
import org.eclipse.jface.dialogs.InputDialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Shell;
import org.elwiki.permissions.PagePermission;
import org.elwiki.permissions.PermissionFactory;
import org.elwiki_data.AttachmentContent;
import org.elwiki_data.Elwiki_dataFactory;
import org.elwiki_data.WikiPage;

import erwiki.api.attachment.AttachmentManager;
import erwiki.api.auth.AuthorizationManager;
import erwiki.api.core.WikiSession;
import erwiki.api.exceptions.ProviderException;
import erwiki.api.exceptions.WikiException;
import erwiki.api.rwc.RWC;
import erwiki.ui.app.parts.attachments.EventsAttachmentsView;
import jakarta.inject.Inject;
import jakarta.inject.Named;

public class AddAttachmentHandler {

	private static final Logger log = Logger.getLogger(AddAttachmentHandler.class);

	@Inject
	AttachmentManager attachmentManager;

	@Inject
	AuthorizationManager authorizationManager;

	@Inject
	IEventBroker eventBroker;

	/**
	 * Используя RAP-диалог FileDialog - загружает файлы во временный каталог, затем содержимое этих
	 * файлов передает в {@link AttachmentManager}.</br>
	 * Временный каталог создается в "java.io.tmpdir", после завершения работы - удаляет его.</br>
	 *
	 * @param shell
	 */
	@Execute
	public void addAttachment(@Named(IServiceConstants.ACTIVE_SHELL) Shell shell) {
		Path tempDirectory = null;
		try {
			FileDialog fileDialog = new FileDialog(shell, SWT.SHELL_TRIM | SWT.APPLICATION_MODAL);
			fileDialog.setFilterExtensions(new String[] { "*.txt", "*.*" }); // :FVK: - задать расширения.
			fileDialog.setText("Upload Attachment File"); // TODO: локализовать строку.
			int uploadMaxSize = (authorizationManager.hasAdminPermissions()) ? Integer.MAX_VALUE
					: attachmentManager.propsMaxAllowedUploadSize();
			fileDialog.setUploadSizeLimit(uploadMaxSize);
			tempDirectory = Files.createTempDirectory("att_erwiki");
			fileDialog.setUploadDirectory(tempDirectory.toFile());
			if (fileDialog.open() != null) {
				storeAttachments(shell, fileDialog);
			}
		} catch (Exception e) {
			log.error("Fail upload files.", e);
			MessageDialog.openError(shell, "Error", e.getMessage());
		} finally {
			try {
				if (tempDirectory != null) {
					FileUtils.deleteQuietly(tempDirectory.toFile());
				}
			} catch (Exception e) {
			}
		}
	}

	/**
	 * @param shell
	 * @param fileDialog
	 */
	protected void storeAttachments(Shell shell, FileDialog fileDialog) {
		// FIXME: перенести проверку допустимости загрузки файлов - на разрешение этого action(виджета).
		WikiPage wikiPage = RWC.INSTANCE.getPage();
		WikiSession wikiSession = RWC.INSTANCE.getWikiSession();
		/* Check if we're allowed to do this?
		 */
		Permission permission = PermissionFactory.getPagePermission(wikiPage, PagePermission.UPLOAD_ACTION);
		if (authorizationManager.checkPermission(wikiSession, permission)) {
			String changenote = null;
			InputDialog dlg;
			dlg = new InputDialog(shell, "Input", "Enter note of attachment", null, null);
			if (dlg.open() == Window.OK) {
				changenote = dlg.getValue();
			}

			for (String filename : fileDialog.getFileNames()) {
				File file = null;
				try {
					String targetName;
					try {
						targetName = AttachmentManager.validateFileName(filename);
					} catch (WikiException e) {
						MessageDialog.openError(shell, "Error", e.getMessage());
						continue;
					}

					// Администратор - может загружать файлы любых типов.
					String extension = IPath.fromOSString(filename).getFileExtension();
					if (!authorizationManager.hasAdminPermissions()
							&& !attachmentManager.isFileTypeAllowed(extension)) {
						MessageDialog.openInformation(shell, "Warning",
								"Files of '." + extension + "' type may not be uploaded to this wiki");
						continue;
					}

					/* Подготовить параметры прикрепления, передать в attachment-менеджер.
					*/
					file = new File(filename);
					long contentLength = FileUtils.sizeOf(file);
					AttachmentContent attContent = Elwiki_dataFactory.eINSTANCE.createAttachmentContent();
					attContent.setCreationDate(new Date());
					attContent.setSize(contentLength);
					Principal user = RWC.INSTANCE.getCurrentUser();
					if (user != null) {
						attContent.setAuthor(user.getName());
					}

					if (changenote != null && changenote.length() > 0) {
						attContent.setChangeNote(changenote);
					}

					try (FileInputStream inputStream = new FileInputStream(file);) {
						attachmentManager.storeAttachment(wikiPage, attContent, targetName, inputStream);
					} catch (ProviderException | IOException e) {
						MessageDialog.openError(shell, "Error", e.getMessage());
					}
				} catch (Exception e) {
					log.error("Fail create attachment file.", e);
				}
			}
			eventBroker.post(EventsAttachmentsView.TOPIC_ATTACHMENTS_UPDATE, "updated");
		}
	}

}
